﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace TShooter.TfsWord.TeamFoundation
{
    public abstract class ObservableCollection<T>: Collection<T>
    {
        public event ListChangedEventHandler ListChanged;

        protected virtual void OnListChanged(ListChangedEventArgs e)
        {
            if (ListChanged != null)
            {
                ListChanged(this, e);
            }
        }

        protected override void ClearItems()
        {
            UnbindAllItems(); 
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, 0));
            base.ClearItems();
        }

        protected override void InsertItem(int index, T item)
        {
            BindToItemNotification(item as INotifyPropertyChanged);
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));

            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            UnbindFromItemNotification(this[index] as INotifyPropertyChanged);
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index, index));

            base.RemoveItem(index);
        }

        protected override void SetItem(int index, T item)
        {
            UnbindFromItemNotification(this[index] as INotifyPropertyChanged);
            BindToItemNotification(item as INotifyPropertyChanged);
            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));

            base.SetItem(index, item);
        }

        private void BindToItemNotification(INotifyPropertyChanged item)
        {
            if (item != null)
            {
                item.PropertyChanged += Item_PropertyChanged;
            }
        }

        private void UnbindFromItemNotification(INotifyPropertyChanged item)
        {
            if (item != null)
            {
                item.PropertyChanged -= Item_PropertyChanged;
            }
        }

        private void UnbindAllItems()
        {
            foreach (var item in this)
            {
                UnbindFromItemNotification(item as INotifyPropertyChanged);
            }
        }

        private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var pd = TypeDescriptor.GetProperties(sender).Find(e.PropertyName, true);

            OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, IndexOf((T) sender), pd));
        }
    }
}
